<?php

namespace iBrand\Component\Order\Models;

use iBrand\Component\Discount\Contracts\DiscountSubjectContract;
use iBrand\Component\Point\Contract\PointSubjectContract;
use iBrand\Component\Payment\Contracts\PaymentsSubjectContract;
use iBrand\Component\Payment\Models\Payment;
use iBrand\Component\Refund\Models\Refund;
use iBrand\Shop\Core\Models\PaymentDetail;
use iBrand\Shop\Core\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Order extends Model implements DiscountSubjectContract, PaymentsSubjectContract, PointSubjectContract
{
    use SoftDeletes;

    const STATUS_TEMP = 0;   //临时订单
    const STATUS_NEW = 1;    //有效订单，待付款
    const STATUS_PAY = 2;    //已支付订单，待发货

    const STATUS_DELIVERED = 3;    //已发货，待收货
    const STATUS_RECEIVED = 4;    //已收货，待评价
    const STATUS_COMPLETE = 5;    //已评价，订单完成

    const STATUS_PAY_PARTLY = 21;    //已经支付部分金额
    const STATUS_CANCEL = 6; //已取消订单
    const STATUS_INVALID = 8;//已作废订单
    const STATUS_REFUND = 7;//有退款订单
    const STATUS_DELETED = 9;//已删除订单

    const TYPE_DEFAULT = 0;//默认类型
    const TYPE_DISCOUNT = 1;//折扣订单
    const TYPE_IN_SOURCE = 2;//内购订单
    const TYPE_GIFT = 3;//礼品订单
    const TYPE_SUIT = 4;//套餐订单

    const TYPE_SHOP = 6;//门店O2O订单

    const TYPE_POINT = 5;//积分商城订单   6是O2O订单
    const TYPE_SECKILL = 7;//秒杀订单
    const TYPE_SHOP_REFUND = 8; //门店售后订单

    /*distribution_status*/
    const DELIVERED_WAIT = 0;  //待发货
    const DELIVERED_STATUS = 1; //已全部发货
    const DELIVERED_PARTLY = 2; //部分发货

    const TYPE_GROUPON = 8;//拼团订单
    const TYPE_FREE_EVENT = 9;//免费活动订单
    const TYPE_MULTI_GROUPON = 10; //小拼团订单

    const TYPE_ACTIVITY_TEMP = 110; //活动订单临时类型
    const TYPE_ACTIVITY = 11; //活动订单

    protected $table = 'el_order';

    protected $guarded = ['id'];

    protected $appends = ['refund_status', 'payment_text', 'balance_paid', 'items_total_yuan', 'total_yuan', 'adjustments_total_yuan', 'used_balance_amount'];

    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        $this->status = self::STATUS_TEMP;
        $this->order_no = build_order_no();
    }

    public function save(array $options = [])
    {
        $order = parent::save($options); // TODO: Change the autogenerated stub

        $this->items()->saveMany($this->getItems());

        $this->adjustments()->saveMany($this->getAdjustments());

        $this->comments()->saveMany($this->comments);

        return $order;
    }

    public function user()
    {
        return $this->belongsTo(User::class)->withDefault();
    }

    public function items()
    {
        return $this->hasMany(OrderItem::class, 'order_id');
    }

    public function adjustments()
    {
        return $this->hasMany(Adjustment::class);
    }

    public function specialTypes()
    {
        return $this->hasMany(SpecialType::class);
    }

    public function payments()
    {
        return $this->hasMany(Payment::class);
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }

    public function refunds()
    {
        return $this->hasMany(Refund::class);
    }

    public function coupon()
    {
        return $this->belongsToMany('iBrand\Component\Discount\Models\Coupon', 'el_order_adjustment', 'order_id', 'origin_id');
    }

    public function getCoupon()
    {
        return $this->coupon()->wherePivot('origin_type', 'coupon')->first();
    }

    /**
     * get subject total amount
     *
     * @return int
     */
    public function getSubjectTotal()
    {
        return $this->getItemsTotal();
    }

    /**
     * get subject count item
     *
     * @return int
     */
    public function getSubjectCount()
    {
        return $this->getTotalQuantity();
    }

    /**
     * {@inheritdoc}
     */
    public function getTotalQuantity()
    {
        $quantity = 0;

        foreach ($this->items as $item) {
            $quantity += $item->quantity;
        }

        return $quantity;
    }

    private function getItemsTotal()
    {
        return $this->items_total;
    }

    public function countItems()
    {
        return $this->items->count();
    }

    public function countComments()
    {
        return $this->comments->count();
    }

    /**
     * get subject items
     *
     * @return mixed
     */
    public function getItems()
    {
        return $this->items;
    }

    public function getAdjustments()
    {
        return $this->adjustments;
    }

    public function addItem(OrderItem $item)
    {
        if ($this->hasItem($item) AND !isset($item->item_meta['dynamic_sku'])) {
            return;
        }

        $this->items_total += $item->getTotal();
        $this->items->add($item);
        $this->recalculateTotal();
        $this->recalculateCount();
    }

    public function hasItem(OrderItem $item)
    {
        return $this->items->contains(function ($value, $key) use ($item) {
            return $item->item_id == $value->item_id AND $item->type = $value->type;
        });
        // return $this->items->contains('goods_id', $item->goods_id);
    }

    public function recalculateItemsTotal()
    {
        $items_total = 0;

        foreach ($this->items as $item) {
            $items_total += $item->units_total;
        }

        $this->items_total = $items_total;
        $this->recalculateTotal();
    }

    public function recalculateTotal()
    {
        $this->total = $this->items_total + $this->adjustments_total;

        if ($this->total < 0) {
            $this->total = 0;
        }
    }

    protected function recalculateCount()
    {
        $this->count = $this->getTotalQuantity();
    }

    /**
     * @param $adjustment
     *
     * @return mixed
     */
    public function addAdjustment($adjustment)
    {
        if (!$this->hasAdjustment($adjustment)) {
            $this->adjustments->add($adjustment);
            $this->addToAdjustmentsTotal($adjustment);
        }
    }

    public function hasAdjustment(Adjustment $adjustment)
    {
        return $this->adjustments->contains(function ($value, $key) use ($adjustment) {
            if ($adjustment->order_item_id) {
                return $adjustment->origin_type == $value->origin_type
                    AND $adjustment->origin_id == $value->origin_id
                    AND $adjustment->order_item_id == $value->order_item_id;
            }

            return $adjustment->origin_type == $value->origin_type
                AND $adjustment->origin_id == $value->origin_id;
        });
    }

    protected function addToAdjustmentsTotal(Adjustment $adjustment)
    {
        $this->adjustments_total += $adjustment->amount;
        $this->recalculateTotal();
    }

    public function addPayment(Payment $payment)
    {
        if (!$this->hasPayment($payment)) {
            $this->payments->add($payment);
        }
    }

    public function hasPayment(Payment $payment)
    {
        return $this->payments->contains(function ($value, $key) use ($payment) {
            return $payment->channel = $value->channel;
        });
    }

    public function getPaidAmountAttribute()
    {
        return $this->getPaidAmount();
    }

    public function getUsedBalanceAmountAttribute()
    {
        if ($this->payments->count() === 0) {
            return 0;
        }

        $amount = 0;
        foreach ($this->payments as $item) {
            if ($item->status == Payment::STATUS_COMPLETED) {
                if ($item->channel == 'balance') {
                    $amount += $item->amount;
                }
            }
        }

        return $amount;
    }

    public function getPaidAmount()
    {
        if ($this->payments->count() === 0) {
            return 0;
        }

        $amount = 0;
        foreach ($this->payments as $item) {
            if ($item->status == Payment::STATUS_COMPLETED) {
                $amount += $item->amount;
            }
        }

        return $amount;
    }

    public function getNeedPayAmount()
    {
        return $this->total - $this->getPaidAmount();
    }

    /**
     * get payment subject
     *
     * @return mixed-
     */
    public function getSubject()
    {
        if ($this->countItems() > 0) {
            return $this->getItems()->first()->item_name . ' 等' . $this->countItems() . '件商品';
        }
        throw new \Exception('no items on order');
    }

    public function getRefundStatusAttribute()
    {
        $refunds = $this->refunds->where('status', '<>', 3);

        //$refunds = $this->refunds()->where('status', '<>', 3)->get();
        if ($refunds->count() > 0) {
            return $refunds->first()->type;
        }

        return 0;
    }

    /**
     * get subject user
     *
     * @return mixed
     */
    public function getSubjectUser()
    {
        return $this->user;
    }

    public function getCurrentTotal()
    {
        return $this->total;
    }

    public function getPaymentTextAttribute()
    {
        $channels = $this->payments->pluck('channel');
        $text = [];
        foreach ($channels as $channel) {
            switch ($channel) {
                case 'alipay_wap':
                    $text[] = "支付宝手机网页支付";
                    break;
                case 'alipay_pc_direct':
                    $text[] = "支付宝 PC 网页支付";
                    break;
                case 'wx_pub':
                    $text[] = '微信';
                    break;
                case 'wx_lite':
                    $text[] = "小程序支付";
                    break;
                case 'balance':
                    $text[] = '余额';
                    break;

                case 'wx_pub_qr':
                    $text[] = '微信扫码';
                    break;

                case 'ali_scan_pay':
                    $text[] = '支付宝扫码';
                    break;

                case 'pop_cash_pay':
                    $text[] = '刷卡';
                    break;

                case 'cash_pay':
                    $text[] = '现金';
                    break;

                default:
                    $text[] = '其他';
                    break;
            }
        }

        if (count($text) > 0) {
            return implode(" ", $text);
        }

        return '其他';
    }

    public function getItemsTotalYuanAttribute()
    {
        return number_format($this->items_total / 100, 2, ".", "");
    }

    public function getTotalYuanAttribute()
    {
        return number_format($this->total / 100, 2, ".", "");
    }

    public function getAdjustmentsTotalYuanAttribute()
    {
        return number_format($this->adjustments_total / 100, 2, ".", "");
    }

    public function getBalancePaidAttribute()
    {

        $amount = 0;

        foreach ($this->payments as $item) {
            if ($item->status == Payment::STATUS_COMPLETED AND $item->channel == 'balance') {
                $amount += $item->amount;
            }
        }

        return $amount;
    }

    /**
     * get subject is paid
     *
     * @return mixed
     */
    public function isPaid()
    {
        return $this->pay_status;
    }

    public function paymentDetail()
    {
        return $this->hasOne(PaymentDetail::class)->withDefault();
    }

    public function getOrderUserNameAttribute()
    {
        $user = $this->user;
        if ($user) {
            if ($user->mobile) {
                return $user->mobile;
            }
            if ($user->name) {
                return $user->name;
            }
            if ($user->nick_name) {
                return $user->nick_name;
            }
        }

        return '/';
    }

}
